package com.tvunetworks.center.user.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.tvunetworks.center.common.constant.LocalConstant;
import com.tvunetworks.center.common.util.JsonUtil;
import com.tvunetworks.center.common.util.MyUtil;
import com.tvunetworks.center.user.service.InstanceService;
import com.tvunetworks.center.user.util.AccessServerUtil;
import com.tvunetworks.center.user.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: tvucc-aggregator
 * @description: InstanceServiceImpl
 * @author lebronchen
 * @create: 2019-12-16 10:59
 **/
@Slf4j
@Service
public class InstanceServiceImpl implements InstanceService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private AccessServerUtil accessServerUtil;

    @Value("${instance.manage.url}")
    private String instanceUrl;
    @Value("${instance.testR.configId}")
    private String configId;
    @Value("${instance.testR.projectType}")
    private String projectType;
    @Value("${serviceNameInAuthorizationService}")
    private String serverName;

    @Value("${instance.url.listAllIds}")
    private String listAllIds;
    @Value("${instance.url.createInstance}")
    private String createInstance;
    @Value("${instance.url.shutdownInstance}")
    private String shutdownInstance;

    @Override
    public boolean isTestInstanceExist() throws IOException {
        return this.isInstanceExist();
    }

    @Override
    public synchronized int openTestInstance() throws IOException {
        boolean exist = this.isInstanceExist();
        if (exist) {
            // 实例已经开启，不能重复开启
            return 1;
        }
        this.createInstance();
        return 0;
    }

    @Override
    public int shutdownTestInstance() throws IOException {
        List<String> list = this.listInstance();
        if (CollectionUtils.isEmpty(list)) {
            // 没有开启实例
            return 1;
        }
        for (String instanceId : list) {
            this.shutdownInstance(instanceId);
        }
        return 0;
    }



    private boolean createInstance() throws IOException {
        String url = createInstance;
        if (!StringUtils.startsWith(url, "http://")) {
            url = "http://" + url;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add(LocalConstant.API_HEADER_PARAM_KEY, accessServerUtil.generatorAccess());

        Map<String, String> param = new HashMap<>();
        param.put("type", "ConfigId");
        param.put("configId", configId);
        param.put("origin", "serverName");
        HttpEntity httpEntity = new HttpEntity(JsonUtil.toJsonStr(param), headers);

        ResponseEntity<String> responseEntity;
        log.info("Instance Service CreateInstance url:{} pram:[{}]", url, param);
        try {
            responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (RestClientException e) {
            log.error(e.toString(), e);
            log.info("Instance Service CreateInstance Http error url:{} pram:[{}]", url, param);
            return false;
        }

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            log.info("Instance Service CreateInstance HttpStatus not 200 url:{} pram:[{}] responseEntity:[{}]", url, param, responseEntity);
            return false;
        }
        String result = responseEntity.getBody();
        log.info("Instance Service CreateInstance HttpStatus result url:{} pram:[{}] result:[{}]", url, param, result);

        JsonNode jsonNode = MyUtil.MAPPER.readTree(result);
        if (!(jsonNode.has("errorCode") && "0x0".equalsIgnoreCase(jsonNode.get("errorCode").asText()))) {
            log.info("Instance Service CreateInstance HttpStatus result not success url:{} pram:[{}] result:[{}]", url, param, result);
            return false;
        }
        return true;
    }

    private boolean shutdownInstance(String instanceId) throws IOException {
        String url = shutdownInstance;
        if (!StringUtils.startsWith(url, "http://")) {
            url = "http://" + url;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add(LocalConstant.API_HEADER_PARAM_KEY, accessServerUtil.generatorAccess());

        Map<String, String> param = new HashMap<>();
        param.put("instanceId", instanceId);
        HttpEntity httpEntity = new HttpEntity(JsonUtil.toJsonStr(param), headers);

        ResponseEntity<String> responseEntity;
        log.info("Instance Service ShutdownInstance url:{} pram:[{}]", url, param);
        try {
            responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (RestClientException e) {
            log.error(e.toString(), e);
            log.info("Instance Service ShutdownInstance Http error url:{} pram:[{}]", url, param);
            return false;
        }

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            log.info("Instance Service ShutdownInstance HttpStatus not 200 url:{} pram:[{}] responseEntity:[{}]", url, param, responseEntity);
            return false;
        }
        String result = responseEntity.getBody();
        log.info("Instance Service ShutdownInstance HttpStatus result url:{} pram:[{}] result:[{}]", url, param, result);

        JsonNode jsonNode = MyUtil.MAPPER.readTree(result);
        if (!(jsonNode.has("errorCode") && "0x0".equalsIgnoreCase(jsonNode.get("errorCode").asText()))) {
            log.info("Instance Service ShutdownInstance HttpStatus result not success url:{} pram:[{}] result:[{}]", url, param, result);
            return false;
        }
        return true;
    }

    private boolean isInstanceExist() throws IOException {
        List<String> list = listInstance();
        return !CollectionUtils.isEmpty(list);
    }

    private List<String> listInstance() throws IOException {
        String url = listAllIds;
        if (!StringUtils.startsWith(url, "http://")) {
            url = "http://" + url;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add(LocalConstant.API_HEADER_PARAM_KEY, accessServerUtil.generatorAccess());

        Map<String, String> param = new HashMap<>();
        param.put("imageType", projectType);
        HttpEntity httpEntity = new HttpEntity(JsonUtil.toJsonStr(param), headers);

        ResponseEntity<String> responseEntity;
        log.info("Instance Service listAllIds url:{} pram:[{}]", url, param);
        try {
            responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (RestClientException e) {
            log.error(e.toString(), e);
            log.info("Instance Service listAllIds Http error url:{} pram:[{}]", url, param);
            return null;
        }

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            log.info("Instance Service listAllIds HttpStatus not 200 url:{} pram:[{}] responseEntity:[{}]", url, param, responseEntity);
            return null;
        }
        String result = responseEntity.getBody();
        log.info("Instance Service listAllIds HttpStatus result url:{} pram:[{}] result:[{}]", url, param, result);

        JsonNode jsonNode = MyUtil.MAPPER.readTree(result);
        if (!(jsonNode.has("errorCode") && "0x0".equalsIgnoreCase(jsonNode.get("errorCode").asText()))) {
            log.info("Instance Service listAllIds HttpStatus result not success url:{} pram:[{}] result:[{}]", url, param, result);
            return null;
        }
        JsonNode instanceIds = jsonNode.get("result");
        if (instanceIds == null || instanceIds.size() == 0) {
            return null;
        }
        List<String> resultList = new ArrayList<>();
        for (JsonNode instanceId : instanceIds) {
            resultList.add(instanceId.asText());
        }
        return resultList;
    }
}
